/***************************************************
 ** @Desc : This file for sql动态查询 构造where
 ** @Time : 2018.10.19 15:19 
 ** @Author : Joker
 ** @File : generate_sql
 ** @Last Modified by : Joker
 ** @Last Modified time: 2019-5-29 10:37:16
 ** @Software: GoLand
****************************************************/
package utils

import (
	"reflect"
	"strings"
	"time"
)

type GenerateSQL struct{}

//	generate where
//	1. between的参数必须两个,即start和end必须同时存在或同时没有,违反了此条件,where语句依然正确,但是args不正确
//	2. between参数必须小的声明在大的上面
//	3. like参数 "*like" 匹配 "%xxx", "*like*"和"like"匹配"%xxxx%","like*"匹配"xxx%"
func (the *GenerateSQL) GenWhereByStruct(pm interface{}) (string, []interface{}) {
	valueOf := reflect.ValueOf(pm)
	typeOf := reflect.TypeOf(pm)
	tagTmp := ""
	whereMap := make([][]string, 0)
	args := make([]interface{}, 0)

	for i := 0; i < valueOf.NumField(); i++ {
		tagTmp = typeOf.Field(i).Tag.Get("column")
		if strings.Compare("-", tagTmp) == 0 || tagTmp == "" {
			continue
		}
		cons := strings.Split(tagTmp, ",")
		if !the.IfValueIsNil(valueOf.Field(i).Interface()) {
			// 判断条件符号
			if strings.Compare("*like", cons[2]) == 0 {
				cons[2] = "like"
				args = append(args, "%"+valueOf.Field(i).Interface().(string))
			} else if strings.Compare("like*", cons[2]) == 0 {
				cons[2] = "like"
				args = append(args, valueOf.Field(i).Interface().(string)+"%")
			} else if strings.Compare("*like*", cons[2]) == 0 || strings.Compare("like", cons[2]) == 0 {
				cons[2] = "like"
				args = append(args, "%"+valueOf.Field(i).Interface().(string)+"%")
			} else {
				args = append(args, valueOf.Field(i).Interface())
			}

			//拼接条件
			if valueOf.Field(i).Interface().(string) != "" || strings.Compare("0", valueOf.Field(i).Interface().(string)) != 0 {
				if len(whereMap) == 0 {
					whereMap = append(whereMap, []string{
						"", cons[1], cons[2],
					})
				} else {
					whereMap = append(whereMap, []string{
						cons[0], cons[1], cons[2],
					})
				}
			} else {
				//去掉默认值
				continue
			}

			if strings.Compare("between", cons[2]) == 0 {
				i++
				args = append(args, valueOf.Field(i).Interface())
			}
		}
	}
	where := the.GenWhere(whereMap)
	return where, args
}

// generate where through a where [][]string
func (*GenerateSQL) GenWhere(wh [][]string) (rs string) {
	if len(wh) != 0 {
		rs += " where "
		for _, v := range wh {
			//v[0]表示性质：and/or
			//v[1]表示field：name/age...
			//v[2]表示条件符号：=,>,<,like
			if strings.Compare("between", v[2]) == 0 {
				rs += " " + v[0] + " " + v[1] + " " + "between" + " ? " + " and " + " ? "
				continue
			}
			if strings.Compare("in", v[2]) == 0 {
				rs += " " + v[0] + " " + v[1] + " in " + v[3]
				continue
			}
			rs += " " + v[0] + " " + v[1] + " " + v[2] + " ? "
		}
	}
	return rs
}

// judge default value
func (*GenerateSQL) IfValueIsNil(arg interface{}) bool {
	if arg == nil {
		return true
	}
	switch  v := arg.(type) {
	case int, int8, int16, int32, int64, float32, float64:
		if v == 0 {
			return true
		}
	case string:
		if v == "" || strings.Compare("%%", v) == 0 || strings.Compare("%", v) == 0 {
			return true
		}
	case *string, *int, *int8, *int16, *int32, *int64, *float32, *float64:
		if v == nil {
			return true
		}
	case time.Time:
		return v.IsZero()
	default:
		return false
	}
	return false
}

// remove value of nil
func (the *GenerateSQL) RemoveValueOfZero(se []interface{}) []interface{} {
	if len(se) == 0 {
		return se
	}
	for i, v := range se {
		if the.IfValueIsNil(v) {
			se = append(se[:i], se[i+1:]...)
			return the.RemoveValueOfZero(se)
			break
		}
	}
	return se
}
